import logging
from collections import deque

from configs import config


logger = logging.getLogger(__name__)


class DeviceHandler:

    def __init__(self, *, handler, sn):
        self.handler = handler
        self.__sn = sn
        self.token = config.START_TOKEN

    @property
    def sn(self):
        return self.__sn

    @sn.setter
    def sn(self, sn):
        self.__sn = sn

    def reset_token(self):
        self.token = config.START_TOKEN

    def get_token(self):
        if self.token > config.MAX_TOKEN:
            self.reset_token()
        token = self.token
        self.token += 1
        return token

    def __str__(self):
        return self.sn


class ConnectionHandler:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = object.__new__(cls)
        return cls._instance

    def __init__(self):
        self.allowed = deque(maxlen=1)
        self.alive_handler_dict = dict()

    def get_alive_handler(self, *, sn):
        handler = self.alive_handler_dict.get(sn, {}).get('handler', None)
        if not handler:
            logger.warning(f'device: {sn} handler not found')
        return handler

    def get_allowed(self):
        return self.allowed[-1] if self.allowed else None

    def add(self, *, handler, data):
        if not isinstance(data, dict):
            logger.warning(f'not connection request, ignore')
            return
        sn = data['content']['sn'].decode()
        self._handler_init(handler=handler, sn=sn)
        self.allowed.append(handler)
        self.alive_handler_dict[sn] = dict(handler=handler, collect=-1)

    @staticmethod
    def _handler_init(*, handler, sn):
        handler.token = config.START_TOKEN
        handler.sn = sn
        handler.hz = 1000
        handler.m = 3
        handler.ip = handler.client_address[0]
        handler.upload_data = None
        handler.data = None

    def delete(self, *, sn):
        if sn in self.alive_handler_dict:
            self.alive_handler_dict.pop(sn)
        if self.allowed and sn == self.allowed[0].sn:
            self.allowed.pop()

    @staticmethod
    def reset_token(handler):
        handler.token = config.START_TOKEN

    def get_token(self, handler):
        if handler.token > config.MAX_TOKEN:
            self.reset_token(handler)
        token = handler.token
        handler.token += 1
        return token


connection = ConnectionHandler()
